//
// Created by xiexiangping on 23-04-17
//
#include "audioCollectionEncode.h"

bool audioCollectionEncode::initStream() {

    device = "audio=麦克风阵列 (适用于数字麦克风的英特尔® 智音技术)";
    //device = "audio=外部麦克风 (Realtek(R) Audio)";

    int ret;

    swrCtx = NULL;

    AVDictionary *options = NULL;
    av_dict_set(&options, "sample_rate", "44100", 0); // 采样率设置为 44100 Hz
    av_dict_set(&options, "frame_size", "1024", 0); // 帧大小设置为 1024
    //av_dict_set(&options, "audio_buffer_size", "39", 0); // 设置音频缓冲区大小

    fmtCtx = avformat_alloc_context();
    const AVInputFormat* inputFormat = av_find_input_format("dshow");

    if (avformat_open_input(&fmtCtx, device.c_str(), inputFormat, &options) != 0) {
        printf("avformat_open_input fail\n");
        return false;
    } else {
        printf("avformat_open_input sucess\n");
    }

    if (avformat_find_stream_info(fmtCtx, NULL) < 0) {
        printf("avformat_find_stream_info fail\n");
        return false;
    } else {
        printf("avformat_find_stream_info sucess\n");
    }

    //std::cout << "fmtCtx:" << fmtCtx->fps_probe_size << std::endl;

    //av_dump_format(vFmtCtx, 0, "video device", 0);    // 打印输入文件信息

    streamIndex = -1;


    for (int i = 0; i < fmtCtx->nb_streams; ++i) {
        if (fmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
            streamIndex = 0;
        }
    }

    if (streamIndex != 0) {
        printf("no cin\n");
        return false;
    }

    const AVCodec* codec = avcodec_find_decoder(fmtCtx->streams[0]->codecpar->codec_id);

    //printf("codecid = %x\n", fmtCtx->streams[0]->codecpar->codec_id);

    // 根据解码器名称查找解码器
    if (!codec) {
        printf("Cannot find decoder!\n");
        return false;
    }
    else {
        printf("find decoder success\n");
    }

    pCodecCtx = avcodec_alloc_context3(codec);

    AVCodecParameters *codecParams = fmtCtx->streams[0]->codecpar;

    //将AVCodecParameters的值复制到AVCodecContext 中
    if (avcodec_parameters_to_context(pCodecCtx, codecParams) < 0) {
        printf("AVCodecParameters copy to AVCodecContext error!\n");
        return false;
    }
    else {
        printf("AVCodecParameters copy to AVCodecContext success!\n");
    }


    if (avcodec_open2(pCodecCtx, codec, NULL)) {
        printf("avcodec_open2 fail\n");
        return false;
    }
    else {
        printf("avcodec_open2 success\n");
    }

    //fmtCtx->streams[0]->attached_pic.size = 1024;
    std::cout << "fmtCtx->streams[0]->attached_pic.size:" << fmtCtx->streams[0]->attached_pic.size << std::endl;

    printf("Sample Rate: %d Hz\n", fmtCtx->streams[0]->codecpar->sample_rate);
    printf("Channels: %d\n", fmtCtx->streams[0]->codecpar->channels);
    printf("Format: %d\n", fmtCtx->streams[0]->codecpar->format);


    // 初始化音频重采样上下文
    swrCtx = swr_alloc_set_opts(NULL,
                                av_get_default_channel_layout(CHANNELS),
                                OUTPUT_FORMAT,
                                SAMPLE_RATE,
                                av_get_default_channel_layout(codecParams->channels),
                                (AVSampleFormat)codecParams->format,
                                codecParams->sample_rate,
                                0,
                                NULL);

    if (!swrCtx) {
        printf("Failed to allocate SwrContext\n");
        ret = AVERROR(ENOMEM);
        return false;
    }

    // 初始化音频重采样参数
    ret = swr_init(swrCtx);
    if (ret < 0) {
        printf("Failed to initialize SwrContext\n");
        return false;
    }

    return true;

}

void audioCollectionEncode::read() {

    int ret;
    AVPacket packet;

    // 初始化音频包和帧
    av_init_packet(&packet);
    packet.data = NULL;
    packet.size = 0;

    AVFrame *frame = NULL;
    frame = av_frame_alloc();
    if (!frame) {
        printf("Failed to allocate frame\n");
        //ret = AVERROR(ENOMEM);
        return;
    }


//    FILE *outputFile = NULL;
//    outputFile = fopen(OUTPUT_FILENAME, "wb");
//    if (!outputFile) {
//        printf("Failed to open output file\n");
//        ret = AVERROR_UNKNOWN;
//        return;
//    }



    // 3. 查找音频编码器
    const AVCodec *codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec) {
        printf("找不到 AAC 编码器\n");
        //avformat_free_context(formatCtx);
        return;
    }

    // 4. 编码器上下文设置参数
    codecCtx = avcodec_alloc_context3(codec);
    if (!codecCtx) {
        printf("无法分配 AVCodecContext\n");
        //avformat_free_context(formatCtx);
        return;
    }

    //std::cout << "xxx:" << av_get_channel_layout_nb_channels(codecCtx->channel_layout) << std::endl;

    codecCtx->bit_rate = 2822400; // 输出音频数据比特率
    codecCtx->sample_fmt = AV_SAMPLE_FMT_FLTP; // 输入音频数据采样格式
    codecCtx->sample_rate = 44100; // 输入音频数据采样率
    codecCtx->channel_layout = AV_CH_LAYOUT_STEREO;
    codecCtx->channels = 2; // 输入音频数据通道数
    codecCtx->codec_type = AVMEDIA_TYPE_AUDIO;


    // 5. 打开音频编码器
    ret = avcodec_open2(codecCtx, codec, NULL);
    if (ret < 0) {
        //printf("无法打开音频编码器: %s\n", av_err2str(ret));
        avcodec_free_context(&codecCtx);
        //avformat_free_context(formatCtx);
        return;
    }



    while (true) {
        //calFrameFps();
        //printf("audio fps = %f\n", frameFps);

        //std::cout << "audio read" << std::endl;

        ret = av_read_frame(fmtCtx, &packet);

        //std::cout << "packet size = " << packet.size << std::endl;

        if (ret == AVERROR_EOF) {
            printf("End of file\n");
            break;
        } else if (ret < 0) {
            printf("Failed to read frame\n");
            break;;
        }

        //std::cout << "packet.stream_index = " << packet.stream_index << std::endl;
        //std::cout << "streamIndex = " << streamIndex << std::endl;

        if (packet.stream_index == streamIndex) {

            ret = avcodec_send_packet(pCodecCtx, &packet);
            if (ret != 0) {
                printf("Failed to send packet to decoder\n");
                break;
            }


            while(true) {

                ret = avcodec_receive_frame(pCodecCtx, frame);

                if(ret == 0){
                    //printf("ret = %d\n", ret);
                }


                if (ret != 0) {
                    //printf("ret != 0\n");
                    break;
                }

                // 分配输出音频帧
                dstFrame = av_frame_alloc();
                if (!dstFrame) {
                    // 输出音频帧分配失败，处理错误
                    printf("dstFrame alloc fail !\n");
                    swr_free(&swrCtx);
                    return;
                }

                // 计算输出音频帧的大小
                int dst_nb_samples = av_rescale_rnd(swr_get_delay(swrCtx, SAMPLE_RATE) + frame->nb_samples, SAMPLE_RATE, frame->sample_rate, AV_ROUND_UP);

                // 设置输出音频帧的参数
                dstFrame->channel_layout = av_get_default_channel_layout(CHANNELS);
                dstFrame->format = AV_SAMPLE_FMT_FLTP;
                dstFrame->sample_rate = frame->sample_rate;
                //dstFrame->nb_samples = dst_nb_samples;
                dstFrame->nb_samples = dst_nb_samples;

                //std::cout << "dst_nb_samples:" << dst_nb_samples << std::endl;

                // 分配输出音频帧的数据缓冲区
                ret = av_frame_get_buffer(dstFrame, 0);
                if (ret < 0) {
                    // 输出音频帧数据缓冲区分配失败，处理错误
                    printf("audio dst frame alloc fail !\n");
                    av_frame_free(&dstFrame);
                    swr_free(&swrCtx);
                    return;
                }

                //执行重采样
                int ret = swr_convert(swrCtx, dstFrame->data, dst_nb_samples, (const uint8_t**)frame->data, frame->nb_samples);

                if (ret < 0) {
                    // 音频帧重采样失败，处理错误
                    printf("resampling fail\n");
                    av_frame_free(&dstFrame);
                    swr_free(&swrCtx);
                    return;
                }

                int resampled_data_size = av_samples_get_buffer_size(NULL, CHANNELS, dst_nb_samples, OUTPUT_FORMAT, 1);

                //std::cout << "resampled_data_size:" << resampled_data_size << std::endl;

                int oneChannelDataSize = resampled_data_size / CHANNELS;

                //std::cout << "oneChannelDataSize:" << oneChannelDataSize << std::endl;

                AVPacket *encodePkt = encodeAudioFrame(oneChannelDataSize);



                // 释放重采样后的音频数据内存
                av_frame_free(&dstFrame);

                if(encodePkt == NULL) {
                    //printf("encodePkt == NULL\n");
                    break;
                }

                av_packet_unref(encodePkt);
            }


            av_packet_unref(&packet);

        }



    }

    if (frame) {
        av_frame_free(&frame);
    }

//    if (swrCtx) {
//        swr_free(&swrCtx);
//    }

    if (pCodecCtx) {
        avcodec_free_context(&pCodecCtx);
    }

//    if (inputFormatCtx) {
//        avformat_close_input(&inputFormatCtx);
//    }
}

//oneChannelDataSize为整个数据帧单通道大小（88400）
AVPacket *audioCollectionEncode::encodeAudioFrame(int oneChannelDataSize) {

    int leftSize = 0;
    int rightSize = 0;

    uint8_t *audioLeft = (uint8_t*)malloc(oneChannelDataSize);
    uint8_t *audioRight = NULL;

    //std::cout << "oneChannelDataSize:" << oneChannelDataSize << std::endl;

    memcpy(audioLeft, dstFrame->data[0], oneChannelDataSize);

    if(CHANNELS == 2) {
        audioRight = (uint8_t*)malloc(oneChannelDataSize);
        memcpy(audioRight, dstFrame->data[1], oneChannelDataSize);
    }

    int index= 0;

    int oneFrameSize = av_samples_get_buffer_size(NULL, CHANNELS, codecCtx->frame_size, codecCtx->sample_fmt, 1);

    int oneChannelSize = oneFrameSize/CHANNELS;

    //std::cout << oneFrameSize << std::endl;

    //由于采集到的数据很大，而编码器一次只需要很少的数据。
    //因此将采集到的数据分成多次传给编码器。
    // 由于平面模式的pcm存储方式为：LLLLLLLLLLLLLLLLLLLLLRRRRRRRRRRRRRRRRRRRRR，因此这里合并完传给编码器就行了
    while(true) {

        if(leftSize < oneChannelDataSize) {

            uint8_t * buffer = (uint8_t *)malloc(oneFrameSize);

            memcpy(buffer, audioLeft + index, oneChannelSize);

            //std::cout << oneFrameSize * CHANNELS << std::endl;

            if(CHANNELS == 2) {
                memcpy(buffer + oneChannelSize, audioRight + index, oneChannelSize);
            }

            //一秒44100采样，一帧1024次采样，那么一帧的时间就是： 1000 / (44100 / 1024) = 23.2199580毫秒
            mAudioPts += 23.2199580;

            AVPacket pkt;
            av_init_packet(&pkt);

            AVPacket *packet = &pkt;


            //8192 = 1024 * 4 * 2
            //std::cout << "oneFrameSize:" << oneFrameSize << std::endl;

            aFrame = av_frame_alloc();

            int oneChannelBufferSize = oneFrameSize / codecCtx->channels; //计算出一个声道的数据
            int nb_samplesize = oneChannelBufferSize / av_get_bytes_per_sample(codecCtx->sample_fmt); //计算出采样点个数(1024)

            //std::cout << "nb_samplesize:" << nb_samplesize << std::endl;

            aFrame->nb_samples = nb_samplesize;
            aFrame->channels = CHANNELS;
            aFrame->format = AV_SAMPLE_FMT_FLTP;

            av_samples_fill_arrays(aFrame->data, aFrame->linesize, buffer, codecCtx->channels, aFrame->nb_samples, codecCtx->sample_fmt, 0);


            int ret = avcodec_send_frame(codecCtx, aFrame);
            if(ret != 0) {
                printf("avcodec_send_frame error !\n");
                return NULL;
            }


            ret = avcodec_receive_packet(codecCtx, packet);
            if(ret != 0) {
                printf("avcodec_receive_packet error\n");
                return NULL;
            }

            //std::cout << "codecCtx->bit_rate:" << codecCtx->bit_rate << std::endl;
            std::cout << "packet->size:" << packet->size << std::endl;

            index += oneChannelSize;
            leftSize += oneChannelSize;

            av_packet_unref(packet);
            //break;

        } else {
            break;
        }

        av_frame_free(&aFrame);

    }


    free(audioLeft);
    free(audioRight);
    return NULL;
    //return pkt;
}
